<#
.SYNOPSIS
Convert manifest file definition to its Dsc resource definition Model

.DESCRIPTION
ManifestFileDefinition must have one property source which define the file to synchronize  

.PARAMETER sourceObject
Required. the file definition to transform

.PARAMETER ServerDefinition
Optional. The Manifest Server which contains the file synchronisation definition
If missing, the function will resolve this object
#>
function ConvertTo-DscFileSynchronisation
{
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [PSObject] 
        $sourceObject,

        [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
        [PSObject] 
        $ServerDefinition

    )
    Process
    {               
        $targetObject = Get-DscBaseObject -SourceObject $sourceObject -ServerDefinition $ServerDefinition
        #Check Mandatory properties
        Assert-ObjectProperty -SourceObject $sourceObject -ObjectIdentifier $targetObject.uniqueKey -PropertyName Source

        #Get specific properties for DSC File Synchronization
        $DestinationPath = Get-FullPath -Object $sourceObject 
        $SourcePath = Get-Value -Object $sourceObject -Value $sourceObject.Source

        $targetObject | Add-Member -MemberType NoteProperty -Name DestinationPath -Value $DestinationPath
        $targetObject | Add-Member -MemberType NoteProperty -Name SourcePath -Value $SourcePath

        Write-Output $targetObject

    }
}


<#
.SYNOPSIS
Convert environment variable definition to its Dsc resource definition Model

.DESCRIPTION
ManifestEnvironmentVariableDefinition must have one property source which define the file to synchronize  

.PARAMETER sourceObject
Required. the environment variable definition to transform

.PARAMETER ServerDefinition
Optional. The Manifest Server which contains the file synchronisation definition
If missing, the function will resolve this object
#>
function ConvertTo-DscEnvironmentVariable
{
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [PSObject] 
        $sourceObject,

        [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
        [PSObject] 
        $ServerDefinition

    )
    Process
    {
        $targetObject = Get-DscBaseObject -SourceObject $sourceObject -ServerDefinition $ServerDefinition
        #Check Mandatory properties
        Assert-ObjectProperty -SourceObject $sourceObject -ObjectIdentifier $targetObject.uniqueKey -PropertiesName Name, ElementType

        #Get specific properties for DSC Environment Variable
        $Name = Get-Value -Object $sourceObject -Value $sourceObject.Name
        $Path = (($sourceObject.Parent.ElementType -eq 'folder') -or ($sourceObject.Parent.ElementType -eq 'file'))
        $Value = Get-EnvironmentVariable -EnvironmentVariable $sourceObject
        $MergePattern = $sourceObject.MergePattern
        if (-not $MergePattern) {$MergePattern = ";"}

        $targetObject | Add-Member -MemberType NoteProperty -Name Name -Value $Name
        $targetObject | Add-Member -MemberType NoteProperty -Name Path -Value $Path
        $targetObject | Add-Member -MemberType NoteProperty -Name Value -Value $Value
        $targetObject | Add-Member -MemberType NoteProperty -Name MergePattern -Value $MergePattern

        Write-Output $targetObject
    }
}



<#
.SYNOPSIS
Convert registry definition to its Dsc resource definition Model

.DESCRIPTION
Registry must have one property source which define the file to synchronize  

.PARAMETER sourceObject
Required. the environment variable definition to transform

.PARAMETER ServerDefinition
Optional. The Manifest Server which contains the file synchronisation definition
If missing, the function will resolve this object
#>
function ConvertTo-DscRegistry
{
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [PSObject] 
        $sourceObject,

        [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
        [PSObject] 
        $ServerDefinition

    )
    Process
    {
        $targetObject = Get-DscBaseObject -SourceObject $sourceObject -ServerDefinition $ServerDefinition
        #Check Mandatory properties
        Assert-ObjectProperty -SourceObject $sourceObject -ObjectIdentifier $targetObject.uniqueKey -PropertiesName UniqueKey, ValueType, ValueName


        #Get specific properties for DSC registry Variable
        $Key = Get-Value -Object $sourceObject -Value $sourceObject.UniqueKey
        $ValueType = $sourceObject.ValueType
        $ValueName = Get-Value -Object $sourceObject -Value $sourceObject.ValueName
        $ValueData = Get-RegistryValue -Registry $sourceObject
        $MergePattern = $sourceObject.MergePattern
        if (-not $MergePattern) {$MergePattern = "`r`n"}

        #Change the uniqueKey with dynamic Value and add the ValueName as a key
        $targetObject.uniqueKey = Get-Value -Object $sourceObject -Value $targetObject.uniqueKey
        $targetObject.uniqueKey = $targetObject.uniqueKey.replace("\",".").replace(" ",".")
        $targetObject.uniqueKey += ".$ValueName"


        $targetObject | Add-Member -MemberType NoteProperty -Name Key -Value $Key
        $targetObject | Add-Member -MemberType NoteProperty -Name ValueType -Value $ValueType
        $targetObject | Add-Member -MemberType NoteProperty -Name ValueName -Value $ValueName
        $targetObject | Add-Member -MemberType NoteProperty -Name ValueData -Value $ValueData
        $targetObject | Add-Member -MemberType NoteProperty -Name MergePattern -Value $MergePattern

        Write-Output $targetObject
    }
}



function ConvertTo-DscFolder
{
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [PSObject] 
        $sourceObject,

        [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
        [PSObject] 
        $ServerDefinition

    )
    Process
    {
        $targetObject = Get-DscBaseObject -SourceObject $sourceObject -ServerDefinition $ServerDefinition
        #Check Mandatory properties
        Assert-ObjectProperty -SourceObject $sourceObject -ObjectIdentifier $targetObject.uniqueKey -PropertiesName Path

        #Get specific properties for DSC Folder Variable
        $FullPath = Get-FullPath -Object $sourceObject
        $targetObject | Add-Member -MemberType NoteProperty -Name FullPath -Value $FullPath

        #Add share configuration
        $share=$null
        if ($sourceObject.share) {$share=$sourceObject.share}
        $targetObject | Add-Member -MemberType NoteProperty -Name Share -Value $Share

        #Add Rights for this folder
        if ($sourceObject.Rights)
        {
            $dscRights = @()
            $sourceObject.Rights | ConvertTo-DscRight -ServerDefinition $ServerDefinition | % {$dscRights += $_}
            $targetObject | Add-Member -MemberType NoteProperty -Name Rights -Value $dscRights
        }


        Write-Output $targetObject
    }
}


function ConvertTo-DscRight
{
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [PSObject] 
        $sourceObject,

        [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
        [PSObject] 
        $ServerDefinition

    )
    Process
    {
        $targetObject = Get-DscBaseObject -SourceObject $sourceObject -ServerDefinition $ServerDefinition
        #Check Mandatory properties
        Assert-ObjectProperty -SourceObject $sourceObject -ObjectIdentifier $targetObject.uniqueKey -PropertiesName AccessMask, AccessType, Principal

        #Get specific properties for DSC Folder Variable
        switch($sourceObject.Parent.ElementType)
        {
            "folder"
            {
                $FullPath = Get-FullPath -Object $sourceObject.Parent
            }
            default
            {
                throw "ConvertTo-DscRight has not yet implementation for Object Type '$($sourceObject.Parent.ElementType)'"
            }
        }
        
        $targetObject | Add-Member -MemberType NoteProperty -Name Path -Value $FullPath

        #Add AccessMask configuration
        #$AccessMask = @()
        #$sourceObject.AccessMask -split "," | % {$maskConvert=[System.Security.AccessControl.FileSystemRights]$_; $AccessMask +=$maskConvert }
        $maskConvert=[System.Security.AccessControl.FileSystemRights]$sourceObject.AccessMask
        $targetObject | Add-Member -MemberType NoteProperty -Name AccessMask -Value $maskConvert


        #Add AccessType and principal for this folder
        $targetObject | Add-Member -MemberType NoteProperty -Name AccessType -Value $SourceObject.AccessType
        $targetObject | Add-Member -MemberType NoteProperty -Name Principal -Value (Get-Value -Object $sourceObject -Value  $SourceObject.Principal)

        Write-Output $targetObject
    }
}




function ConvertTo-DscWindowsFeature
{
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [PSObject] 
        $sourceObject,

        [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
        [PSObject] 
        $ServerDefinition

    )
    Process
    {
        $targetObject = Get-DscBaseObject -SourceObject $sourceObject -ServerDefinition $ServerDefinition
        #Check Mandatory properties
        Assert-ObjectProperty -SourceObject $sourceObject -ObjectIdentifier $targetObject.uniqueKey -PropertiesName UniqueKey

        $IncludeAllSubFeature = $false
        if ($sourceObject.IncludeAllSubFeature) {$IncludeAllSubFeature = $sourceObject.IncludeAllSubFeature}

        $targetObject | Add-Member -MemberType NoteProperty -Name Name -Value $sourceObject.uniqueKey
        $targetObject | Add-Member -MemberType NoteProperty -Name IncludeAllSubFeature -Value $IncludeAllSubFeature


        Write-Output $targetObject
    }
}


function ConvertTo-DscIISWebsite
{
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [PSObject] 
        $sourceObject,

        [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
        [PSObject] 
        $ServerDefinition

    )
    Process
    {
        $targetObject = Get-DscBaseObject -SourceObject $sourceObject -ServerDefinition $ServerDefinition
        #Check Mandatory properties
        Assert-ObjectProperty -SourceObject $sourceObject -ObjectIdentifier $targetObject.uniqueKey -PropertiesName siteName

        $targetObject | Add-Member -MemberType NoteProperty -Name Name -Value (Get-Value -Object $sourceObject -Value $sourceObject.siteName)
        $targetObject | Add-Member -MemberType NoteProperty -Name PhysicalPath -Value (Get-FullPath -Object $sourceObject.Folders.RootExecutionContainerDirectory)

        $BindingInfos = @()
        $targetObject | Add-Member -MemberType NoteProperty -Name BindingInfos -Value $BindingInfos
        $sourceObject.SiteBindings | ForEach-Object {
            
            $BindingInfo = New-Object psobject -Property @{
                                                            Protocol = $_.Protocol
                                                            Port=(Get-Value -Object $sourceObject -Value $_.Port)
                                                          }
            if ($BindingInfo.protocol -eq "https")
            {
                $BindingInfo | Add-Member -MemberType NoteProperty -Name CertificateThumbprint -Value (Get-Value -Object $sourceObject -Value $_.CertificateThumbprint)
                $BindingInfo | Add-Member -MemberType NoteProperty -Name CertificateStoreName -Value (Get-Value -Object $sourceObject -Value $_.CertificateStoreName)
            }                                                          

            $targetObject.BindingInfos += $BindingInfo
         
                                                                          
        }

        #Add properties Management
        $AdditionalProperties = @()
        $targetObject | Add-Member -MemberType NoteProperty -Name AdditionalProperties -Value $AdditionalProperties

        #At site Level
        if ($sourceObject.site)
        {
            $sourceObject.site | Get-Member -MemberType NoteProperty | ? {$_.Name -notin ("configurationName","Parent","Container","ElementType","Level")} | ForEach-Object {

                $propertyName = $_.Name
                $propertyValue = Get-Value -Object $sourceObject.Site -Value $($sourceObject.Site.$propertyName)

                $property = New-Object psobject -Property @{
                                                            Name=$propertyName
                                                            value=$propertyValue
                                                            }
                
                $targetObject.AdditionalProperties += $property
            }                                                                                           
        }

        #At log File Level
        if ($sourceObject.logFile)
        {
            $sourceObject.logFile | Get-Member -MemberType NoteProperty | ? {$_.Name -notin ("configurationName","Parent","Container","ElementType","Level")} | ForEach-Object {

                $configurationName = $sourceObject.LogFile.ConfigurationName
                $propertyName = $_.Name
                $propertyValue = Get-Value -Object $sourceObject.logFile -Value $($sourceObject.logFile.$propertyName)

                $property = New-Object psobject -Property @{
                                                            Name=$propertyName
                                                            ConfigurationName=$configurationName
                                                            value=$propertyValue
                                                            }
                $targetObject.AdditionalProperties += $property
            }                                                                                           
        }


        #At traceFailedRequestsLogging Level
        if ($sourceObject.traceFailedRequestsLogging)
        {
            $sourceObject.traceFailedRequestsLogging | Get-Member -MemberType NoteProperty | ? {$_.Name -notin ("configurationName","Parent","Container","ElementType","Level")} | ForEach-Object {

                $configurationName = $sourceObject.traceFailedRequestsLogging.ConfigurationName
                $propertyName = $_.Name
                $propertyValue = Get-Value -Object $sourceObject.traceFailedRequestsLogging -Value $($sourceObject.traceFailedRequestsLogging.$propertyName)

                $property = New-Object psobject -Property @{
                                                            Name=$propertyName
                                                            ConfigurationName=$configurationName
                                                            value=$propertyValue
                                                            }
                $targetObject.AdditionalProperties += $property
            }                                                                                           
        }


        Write-Output $targetObject
    }
}

function ConvertTo-DscInstallerWrapper
{
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [PSObject] 
        $sourceObject,

        [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
        [PSObject] 
        $ServerDefinition,

        [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
        [PSObject] 
        $BinariesRepositoryManager

    )
    Process
    {
        $targetObject = Get-DscBaseObject -SourceObject $sourceObject -ServerDefinition $ServerDefinition
        #Check Mandatory properties
        Assert-ObjectProperty -SourceObject $sourceObject -ObjectIdentifier $targetObject.uniqueKey -PropertiesName ComponentType,PackageType, PackageName, Name

        #Get the binaries Repository Path
        $BinariesRepositoryPath = $BinariesRepositoryManager.GetRemoteProductPath($sourceObject)

        #Get source directory to store products download on the targeted server
        $sourceDirectory = Get-RootFolder -Server $ServerDefinition -UniqueKey "RootSourceDirectory"
        if (!$sourceDirectory) {throw "Server definition '$($ServerDefinition.UniqueKey)' has no directory definition to store locally products"}

        $localSourceDirectoryPath = Get-FullPath -Object $sourceDirectory
        $LocalPackagePath = [System.IO.Path]::Combine($localSourceDirectoryPath, $sourceObject.packageName)

        if (![String]::IsNullOrEmpty($sourceDirectory.share))
        {
            $RemoteSourceDirectoryPath = [System.IO.Path]::Combine("\\",$ServerDefinition.hostName, $sourceDirectory.share)
            $RemotePackagePath = [System.IO.Path]::Combine($RemoteSourceDirectoryPath, $sourceObject.packageName)
        }


        $targetObject | Add-Member -MemberType NoteProperty -Name Name -Value $sourceObject.Name
        $targetObject | Add-Member -MemberType NoteProperty -Name ComponentType -Value $sourceObject.ComponentType
        $targetObject | Add-Member -MemberType NoteProperty -Name PackageType -Value $sourceObject.PackageType
        $targetObject | Add-Member -MemberType NoteProperty -Name BinariesRepositoryPath -Value $BinariesRepositoryPath
        $targetObject | Add-Member -MemberType NoteProperty -Name LocalSourceDirectory -Value $localSourceDirectoryPath
        $targetObject | Add-Member -MemberType NoteProperty -Name RemoteSourceDirectory -Value $RemoteSourceDirectoryPath
        $targetObject | Add-Member -MemberType NoteProperty -Name LocalPackagePath -Value $LocalPackagePath
        $targetObject | Add-Member -MemberType NoteProperty -Name RemotePackagePath -Value $RemotePackagePath
        $targetObject | Add-Member -MemberType NoteProperty -Name AutoDownload -Value $ServerDefinition.AutoDownload

        switch($sourceObject.PackageType)
        {
            "package"
            {
                $productId = ""
                $InstallArguments = ""
                if ($sourceObject.ProductId) {$productId = $sourceObject.ProductId}
                if ($sourceObject.installArguments) {$InstallArguments = $sourceObject.installArguments}

                $targetObject | Add-Member -MemberType NoteProperty -Name ProductId -Value $productId
                $targetObject | Add-Member -MemberType NoteProperty -Name Arguments -Value $InstallArguments

                if ($sourceObject.Folders.InstallationDirectory)
                {
                    write-warning "Add destination folder to msi package via installation arguments"
                }

            }
            "archive"
            {
                $destination = Get-FullPath $sourceObject.Folders.InstallationDirectory
                if (-not $destination) {throw "Unable to find Installation directory for this object identified by '$($sourceObject.UniqueKey)'"}
                $targetObject | Add-Member -MemberType NoteProperty -Name Destination -Value $destination
            }
            "msdeployPackage"
            {
                $destination = Get-FullPath $sourceObject.Folders.InstallationDirectory
                if (-not $destination) {throw "Unable to find Installation directory for this object identified by '$($sourceObject.UniqueKey)'"}
                $targetObject | Add-Member -MemberType NoteProperty -Name Destination -Value $destination
            }
        }

        Write-Output $targetObject
    }
}


function ConvertTo-DscTomcatInstance
{
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [PSObject] 
        $sourceObject,

        [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
        [PSObject] 
        $ServerDefinition

    )
    Process
    {
        $targetObject = Get-DscBaseObject -SourceObject $sourceObject -ServerDefinition $ServerDefinition
        #Check Mandatory properties
        Assert-ObjectProperty -SourceObject $sourceObject -ObjectIdentifier $targetObject.uniqueKey -PropertiesName serviceName, javahome, StartupType


        $serviceName = Get-Value -Object $sourceObject -Value $sourceObject.ServiceName
        $targetObject | Add-Member -MemberType NoteProperty -Name ServiceName -Value $serviceName
        
        $javahome = Get-Value -Object $sourceObject -Value $sourceObject.javahome
        $targetObject | Add-Member -MemberType NoteProperty -Name JavaHome -Value $javahome

        $StartupType = Get-Value -Object $sourceObject -Value $sourceObject.StartupType
        $targetObject | Add-Member -MemberType NoteProperty -Name StartupType -Value $StartupType

        $CatalinaBase = $sourceObject.Folders.CatalinaBase.FullPath
        if (-not $CatalinaBase) {throw "Unable to find Catalina Base directory for this object identified by '$($sourceObject.UniqueKey)'"}
        $targetObject | Add-Member -MemberType NoteProperty -Name Catalina_Base -Value $CatalinaBase

        $CatalinaHome = $sourceObject.Folders.CatalinaHome.FullPath
        if (-not $CatalinaHome) {throw "Unable to find Catalina Home directory for this object identified by '$($sourceObject.UniqueKey)'"}
        $targetObject | Add-Member -MemberType NoteProperty -Name Catalina_Home -Value $CatalinaHome

        $AlldscRegistries = $sourceObject.Registry | ConvertTo-DscRegistry -ServerDefinition $ServerDefinition
        $MergeRegistries = Merge-Registry -Registries $AlldscRegistries
        $targetObject | Add-Member -MemberType NoteProperty -Name Registry -Value $MergeRegistries
        
        Write-Output $targetObject
    }
}


function ConvertTo-DscTomcatMiddleware
{
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [PSObject] 
        $sourceObject,

        [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
        [PSObject] 
        $ServerDefinition

    )
    Process
    {
        $targetObject = Get-DscBaseObject -SourceObject $sourceObject -ServerDefinition $ServerDefinition
        #Check Mandatory properties
        Assert-ObjectProperty -SourceObject $sourceObject -ObjectIdentifier $targetObject.uniqueKey -PropertiesName executionContainers

        if(-not $ServerDefinition) {$ServerDefinition = Get-Server $sourceObject}

        $tomcatInstances = $sourceObject.executionContainers.Values | ConvertTo-DscTomcatInstance -ServerDefinition $ServerDefinition
        $targetObject | Add-Member -MemberType NoteProperty -Name TomcatInstances -Value $tomcatInstances
              
        Write-Output $targetObject
    }
}



<#
function ConvertTo-DscProductDonwload
{
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [PSObject] 
        $sourceObject,

        [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
        [PSObject] 
        $ServerDefinition,

        [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
        [PSObject] 
        $BinariesRepositoryManager

    )
    Process
    {
        $targetObject = Get-DscBaseObject -SourceObject $sourceObject -ServerDefinition $ServerDefinition
        #Check Mandatory properties
        Assert-ObjectProperty -SourceObject $sourceObject -ObjectIdentifier $targetObject.uniqueKey -PropertiesName Path

        #Get the binaries Repository Path
        $BinariesRepositoryPath = $BinariesRepositoryManager.GetRemoteProductPath($sourceObject)

        #Get source directory to store products download on the targeted server
        $sourceDirectory = Get-RootFolder -Server $ServerDefinition -UniqueKey "RootSourceDirectory"
        if (!$sourceDirectory) {throw "Server definition '$($ServerDefinition.UniqueKey)' has no directory definition to store locally products"}

        $sourceDirectoryPath = Get-FullPath -Object $sourceDirectory
        $LocalPath= = [System.IO.Path]::Combine($sourceDirectoryPath, $_.packageName)

        if (![String]::IsNullOrEmpty($sourceDirectory.share))
        {
            $networkPath = [System.IO.Path]::Combine("\\",$ServerDefinition.hostName, $sourceDirectory.share)
            $RemotePath = [System.IO.Path]::Combine($networkPath, $_.packageName)
        }
        
        $targetObject | Add-Member -MemberType NoteProperty -Name BinariesRepositoryPath -Value $BinariesRepositoryPath
        $targetObject | Add-Member -MemberType NoteProperty -Name LocalPath -Value $LocalPath
        $targetObject | Add-Member -MemberType NoteProperty -Name RemotePath -Value $RemotePath

        Write-Output $targetObject
    }
}

#>